package org.example.invest.controller;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;

import org.example.invest.model.bo.InvestmentManagementCreateInvestmentInputBO;
import org.example.invest.model.bo.InvestmentManagementDeleteInvestmentInputBO;
import org.example.invest.model.bo.InvestmentManagementGetHistoryAtInputBO;
import org.example.invest.model.bo.InvestmentManagementGetHistoryCountInputBO;
import org.example.invest.model.bo.InvestmentManagementGetInvestmentByTxHashInputBO;
import org.example.invest.model.bo.InvestmentManagementGetInvestmentInputBO;
import org.example.invest.model.bo.InvestmentManagementUpdateInvestmentInputBO;
import org.example.invest.model.bo.InvestmentManagementVerifyDataHashInputBO;
import org.example.invest.service.InvestmentManagementService;
import org.example.invest.utils.CallResponseUtils;
import org.fisco.bcos.sdk.transaction.model.dto.CallResponse;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/investments")
@CrossOrigin
public class InvestmentController {

    private static final Logger logger = LoggerFactory.getLogger(InvestmentController.class);

    @Autowired
    private InvestmentManagementService investmentManagementService;

    // 获取所有投资记录和区块高度
    @GetMapping
    public Map<String, Object> getAllInvestments() {
        Map<String, Object> result = new HashMap<>();
        try {
            // 获取当前区块高度
            String blockNumber = investmentManagementService.getBlockNumber();
            
            // 获取所有投资记录
            List<Map<String, Object>> investments = new ArrayList<>();
            
            // 从ID 1开始遍历查询所有投资记录
            BigInteger i = BigInteger.ONE;
            boolean continueSearch = true;
            
            // 为避免无限循环，设置一个合理的上限
            int maxAttempts = 100;
            int attempts = 0;
            
            while (continueSearch && attempts < maxAttempts) {
                attempts++;
                try {
                    InvestmentManagementGetInvestmentInputBO inputBO = new InvestmentManagementGetInvestmentInputBO();
                    inputBO.set_id(i);
                    
                    CallResponse response = investmentManagementService.getInvestment(inputBO);
                    List<Object> investmentData = CallResponseUtils.getListValues(response);
                    
                    // 确保有数据且是有效投资
                    if (investmentData != null && !investmentData.isEmpty()) {
                        Map<String, Object> investment = new HashMap<>();
                        investment.put("id", i);
                        
                        // 解析投资数据
                        if (investmentData.size() >= 7) {
                            investment.put("investor", investmentData.get(0));
                            investment.put("amount", investmentData.get(1));
                            investment.put("projectName", investmentData.get(2));
                            investment.put("profession", investmentData.get(3));
                            investment.put("dataHash", investmentData.get(4));
                            investment.put("txHash", investmentData.get(5));
                            investment.put("isActive", investmentData.get(6));
                            
                            // 添加所有投资记录到列表，无论是否处于活跃状态
                            investments.add(investment);
                        }
                        
                        // 继续尝试下一个ID
                        i = i.add(BigInteger.ONE);
                    } else {
                        // 如果没有数据，说明该ID不存在，尝试下一个ID
                        i = i.add(BigInteger.ONE);
                        
                        // 如果连续5个ID都不存在，则结束搜索
                        if (attempts > 5 && investments.isEmpty()) {
                            continueSearch = false;
                        }
                    }
                } catch (Exception e) {
                    // 如果查询某个ID失败，可能是该ID不存在，尝试下一个ID
                    i = i.add(BigInteger.ONE);
                    
                    // 如果已经找到了一些投资记录，但连续5次查询都失败，则结束循环
                    if (attempts > 5 && investments.isEmpty()) {
                        continueSearch = false;
                    }
                }
            }
            
            result.put("status", "success");
            result.put("data", investments);
            result.put("blockNumber", blockNumber);
            
        } catch (Exception e) {
            // 更详细的错误处理和日志记录
            e.printStackTrace(); // 在服务器日志中记录详细错误
            result.put("status", "error");
            result.put("message", "获取投资列表失败: " + e.getMessage());
            result.put("blockNumber", "未连接");  // 即使出错也提供一个区块高度占位符
            result.put("data", new ArrayList<>()); // 确保data字段始终存在
        }
        return result;
    }

    // 创建投资记录
    @PostMapping
    public Map<String, Object> createInvestment(@RequestBody Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        try {
            BigInteger amount = new BigInteger(requestBody.get("amount").toString());
            String projectName = (String) requestBody.get("projectName");
            String profession = (String) requestBody.get("profession");

            InvestmentManagementCreateInvestmentInputBO inputBO = new InvestmentManagementCreateInvestmentInputBO();
            inputBO.set_amount(amount);
            inputBO.set_projectName(projectName);
            inputBO.set_profession(profession);

            TransactionResponse response = investmentManagementService.createInvestment(inputBO);
            
            result.put("status", "success");
            result.put("message", "投资记录创建成功");
            result.put("data", response);
            
            // 获取交易哈希
            String txHash = response.getTransactionReceipt().getTransactionHash();
            result.put("txHash", txHash);
            result.put("blockNumber", response.getTransactionReceipt().getBlockNumber());
            
            // 从返回结果中提取投资ID
            String output = response.getTransactionReceipt().getOutput();
            BigInteger investmentId = BigInteger.ZERO;
            if (output != null && !output.isEmpty() && output.length() > 2) {
                // 通常输出是0x开头的16进制数，需要转换
                investmentId = new BigInteger(output.substring(2), 16);
                result.put("investmentId", investmentId);
                
                // 验证：尝试使用合约内部产生的交易哈希查询
                logger.info("合约内部交易哈希逻辑检测中...");
                try {
                    // 获取投资详情
                    InvestmentManagementGetInvestmentInputBO detailInputBO = new InvestmentManagementGetInvestmentInputBO();
                    detailInputBO.set_id(investmentId);
                    CallResponse detailResponse = investmentManagementService.getInvestment(detailInputBO);
                    List<Object> investmentData = CallResponseUtils.getListValues(detailResponse);
                    
                    if (investmentData != null && investmentData.size() >= 6) {
                        // 获取合约内部生成的交易哈希
                        Object contractTxHashObj = investmentData.get(5);
                        if (contractTxHashObj != null) {
                            byte[] contractTxHashBytes = (byte[]) contractTxHashObj;
                            
                            // 将字节数组转换为16进制字符串
                            StringBuilder sb = new StringBuilder("0x");
                            for (byte b : contractTxHashBytes) {
                                sb.append(String.format("%02x", b & 0xff));
                            }
                            String contractTxHash = sb.toString();
                            
                            // 添加到返回结果中
                            result.put("contractInternalTxHash", contractTxHash);
                            
                            // 使用合约内部交易哈希尝试查询
                            BigInteger idByContractTxHash = investmentManagementService.getInvestmentIdByTxHash(contractTxHash);
                            result.put("idByContractTxHash", idByContractTxHash);
                            
                            logger.info("合约内部交易哈希: {}，查询结果: {}", contractTxHash, idByContractTxHash);
                        }
                    }
                } catch (Exception e) {
                    logger.error("验证合约内部交易哈希失败: {}", e.getMessage());
                    result.put("verifyContractTxHashError", e.getMessage());
                }
            }
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "创建投资记录失败: " + e.getMessage());
        }
        return result;
    }

    // 更新投资信息
    @PutMapping("/{id}")
    public Map<String, Object> updateInvestment(@PathVariable("id") BigInteger id, @RequestBody Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        try {
            BigInteger amount = new BigInteger(requestBody.get("amount").toString());
            String projectName = (String) requestBody.get("projectName");
            String profession = (String) requestBody.get("profession");

            InvestmentManagementUpdateInvestmentInputBO inputBO = new InvestmentManagementUpdateInvestmentInputBO();
            inputBO.set_id(id);
            inputBO.set_amount(amount);
            inputBO.set_projectName(projectName);
            inputBO.set_profession(profession);

            TransactionResponse response = investmentManagementService.updateInvestment(inputBO);
            
            result.put("status", "success");
            result.put("message", "投资记录更新成功");
            result.put("data", response);
            result.put("txHash", response.getTransactionReceipt().getTransactionHash());
            result.put("blockNumber", response.getTransactionReceipt().getBlockNumber());
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "更新投资记录失败: " + e.getMessage());
        }
        return result;
    }

    // 删除投资记录（软删除）
    @DeleteMapping("/{id}")
    public Map<String, Object> deleteInvestment(@PathVariable("id") BigInteger id) {
        Map<String, Object> result = new HashMap<>();
        try {
            InvestmentManagementDeleteInvestmentInputBO inputBO = new InvestmentManagementDeleteInvestmentInputBO();
            inputBO.set_id(id);

            TransactionResponse response = investmentManagementService.deleteInvestment(inputBO);
            
            result.put("status", "success");
            result.put("message", "投资记录删除成功");
            result.put("data", response);
            result.put("txHash", response.getTransactionReceipt().getTransactionHash());
            result.put("blockNumber", response.getTransactionReceipt().getBlockNumber());
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "删除投资记录失败: " + e.getMessage());
        }
        return result;
    }

    // 获取投资详情
    @GetMapping("/{id}")
    public Map<String, Object> getInvestment(@PathVariable("id") BigInteger id) {
        Map<String, Object> result = new HashMap<>();
        try {
            InvestmentManagementGetInvestmentInputBO inputBO = new InvestmentManagementGetInvestmentInputBO();
            inputBO.set_id(id);

            CallResponse response = investmentManagementService.getInvestment(inputBO);
            
            result.put("status", "success");
            result.put("data", CallResponseUtils.getListValues(response));
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "获取投资记录失败: " + e.getMessage());
        }
        return result;
    }

    // 通过交易哈希查询投资记录
    @GetMapping("/tx/{txHash}")
    public ResponseEntity<?> getInvestmentByTxHash(@PathVariable String txHash) {
        try {
            logger.info("Fetching investment by transaction hash: {}", txHash);
            
            // 验证交易哈希格式
            if (!txHash.startsWith("0x") || txHash.length() != 66) {
                logger.error("Invalid transaction hash format: {}", txHash);
                Map<String, Object> response = new HashMap<>();
                response.put("error", "无效的交易哈希格式");
                response.put("details", "交易哈希应以0x开头并且长度为66个字符");
                return ResponseEntity.badRequest().body(response);
            }

            // 添加更多的日志输出，帮助调试
            logger.info("Original transaction hash: {}", txHash);
            String txHashWithoutPrefix = txHash.startsWith("0x") ? txHash.substring(2) : txHash;
            logger.info("Transaction hash without prefix: {}", txHashWithoutPrefix);
            
            // 从智能合约获取投资ID
            BigInteger investmentId = investmentManagementService.getInvestmentIdByTxHash(txHash);
            
            // 记录智能合约返回的投资ID
            logger.info("Smart contract returned investment ID: {}", investmentId);
            
            // 如果智能合约返回的ID为0，表示映射不存在
            if (investmentId.equals(BigInteger.ZERO)) {
                Map<String, Object> response = new HashMap<>();
                response.put("status", "success");
                response.put("message", "交易哈希在区块链上未关联到任何投资记录");
                response.put("txHash", txHash);
                response.put("investmentId", 0);
                
                // 添加调试信息
                response.put("possibleReasons", Arrays.asList(
                    "交易可能尚未被确认",
                    "交易可能不是创建投资的交易",
                    "交易哈希可能输入错误",
                    "智能合约中的txHashToId映射可能未正确更新"
                ));
                
                return ResponseEntity.ok(response);
            }
            
            // 获取投资记录
            InvestmentManagementGetInvestmentInputBO detailInputBO = new InvestmentManagementGetInvestmentInputBO();
            detailInputBO.set_id(investmentId);
            CallResponse detailResponse = investmentManagementService.getInvestment(detailInputBO);
            
            if (detailResponse != null) {
                // 记录找到的投资记录
                logger.info("Found investment record: {}", detailResponse);
                return ResponseEntity.ok(CallResponseUtils.getListValues(detailResponse));
            } else {
                // 记录数据库查询结果
                logger.error("Investment record not found in database for ID: {}", investmentId);
                Map<String, Object> response = new HashMap<>();
                response.put("status", "error");
                response.put("message", "在智能合约中找到了投资ID映射，但数据库中不存在对应记录");
                response.put("txHash", txHash);
                response.put("investmentId", investmentId);
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
            }
        } catch (Exception e) {
            logger.error("Error fetching investment by transaction hash: {}", txHash, e);
            Map<String, Object> response = new HashMap<>();
            response.put("status", "error");
            response.put("message", "获取投资记录时发生错误: " + e.getMessage());
            response.put("txHash", txHash);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    // 验证数据哈希
    @GetMapping("/verify")
    public Map<String, Object> verifyDataHash(@RequestParam("id") BigInteger id, @RequestParam("dataHash") String dataHash) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 转换dataHash为bytes32
            byte[] dataHashBytes = hexStringToByteArray(dataHash);
            
            InvestmentManagementVerifyDataHashInputBO inputBO = new InvestmentManagementVerifyDataHashInputBO();
            inputBO.set_id(id);
            inputBO.set_dataHash(dataHashBytes);

            CallResponse response = investmentManagementService.verifyDataHash(inputBO);
            
            result.put("status", "success");
            result.put("verified", CallResponseUtils.getBooleanValue(response, false));
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "验证数据哈希失败: " + e.getMessage());
        }
        return result;
    }

    // 获取投资历史版本数量
    @GetMapping("/history/count")
    public Map<String, Object> getHistoryCount(@RequestParam("dataHash") String dataHash) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 转换dataHash为bytes32
            byte[] dataHashBytes = hexStringToByteArray(dataHash);
            
            InvestmentManagementGetHistoryCountInputBO inputBO = new InvestmentManagementGetHistoryCountInputBO();
            inputBO.set_dataHash(dataHashBytes);

            CallResponse response = investmentManagementService.getHistoryCount(inputBO);
            
            result.put("status", "success");
            result.put("count", CallResponseUtils.getBigIntegerValue(response, BigInteger.ZERO));
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "获取历史版本数量失败: " + e.getMessage());
        }
        return result;
    }

    // 获取投资历史版本详情
    @GetMapping("/history")
    public Map<String, Object> getHistoryAt(
            @RequestParam("dataHash") String dataHash, 
            @RequestParam("index") BigInteger index) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 转换dataHash为bytes32
            byte[] dataHashBytes = hexStringToByteArray(dataHash);
            
            // 先获取历史版本数量，避免索引越界
            InvestmentManagementGetHistoryCountInputBO countInputBO = new InvestmentManagementGetHistoryCountInputBO();
            countInputBO.set_dataHash(dataHashBytes);
            CallResponse countResponse = investmentManagementService.getHistoryCount(countInputBO);
            BigInteger count = CallResponseUtils.getBigIntegerValue(countResponse, BigInteger.ZERO);
            
            // 检查索引是否有效
            if (count.compareTo(BigInteger.ZERO) <= 0) {
                result.put("status", "error");
                result.put("message", "该数据哈希没有历史版本记录");
                return result;
            }
            
            if (index.compareTo(BigInteger.ZERO) < 0 || index.compareTo(count.subtract(BigInteger.ONE)) > 0) {
                result.put("status", "error");
                result.put("message", "索引超出范围，有效范围为0至" + (count.subtract(BigInteger.ONE)));
                return result;
            }
            
            // 索引有效，获取历史版本详情
            InvestmentManagementGetHistoryAtInputBO inputBO = new InvestmentManagementGetHistoryAtInputBO();
            inputBO.set_dataHash(dataHashBytes);
            inputBO.set_index(index);

            CallResponse response = investmentManagementService.getHistoryAt(inputBO);
            
            result.put("status", "success");
            result.put("data", CallResponseUtils.getListValues(response));
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "获取历史版本详情失败: " + e.getMessage());
            e.printStackTrace(); // 增加错误日志记录
        }
        return result;
    }
    
    // 辅助方法：将16进制字符串转换为字节数组
    private byte[] hexStringToByteArray(String hexString) {
        // 使用标准工具方法，确保所有地方使用相同的转换逻辑
        return org.example.invest.utils.CallResponseUtils.standardizeBytes32(hexString);
    }
    
    // 添加调试端点：查看交易哈希的字节表示
    @GetMapping("/debug/txhash/{txHash}")
    public Map<String, Object> debugTxHash(@PathVariable String txHash) {
        Map<String, Object> result = new HashMap<>();
        try {
            logger.info("Debug transaction hash: {}", txHash);
            
            // 转换原始交易哈希为字节数组
            byte[] convertedBytes = hexStringToByteArray(txHash);
            
            // 记录转换过程
            result.put("status", "success");
            result.put("originalTxHash", txHash);
            if (txHash.startsWith("0x")) {
                result.put("withoutPrefix", txHash.substring(2));
            }
            
            // 重新将字节数组转回16进制字符串用于对比
            StringBuilder sb = new StringBuilder();
            for (byte b : convertedBytes) {
                sb.append(String.format("%02x", b & 0xff));
            }
            result.put("reconvertedHex", "0x" + sb.toString());
            result.put("byteLength", convertedBytes.length);
            
            // 使用Service中的转换方法进行对比
            BigInteger investmentId = investmentManagementService.getInvestmentIdByTxHash(txHash);
            result.put("investmentId", investmentId);
            
            // 尝试直接从智能合约查询（未处理的原始交易哈希）
            if (txHash.length() == 66 && txHash.startsWith("0x")) {
                try {
                    // 使用原始Service方法进行对比
                    InvestmentManagementGetInvestmentByTxHashInputBO inputBO = new InvestmentManagementGetInvestmentByTxHashInputBO();
                    inputBO.set_txHash(convertedBytes);
                    CallResponse response = investmentManagementService.getInvestmentByTxHash(inputBO);
                    result.put("directContractResponse", CallResponseUtils.getBigIntegerValue(response, BigInteger.ZERO));
                } catch (Exception e) {
                    result.put("directContractError", e.getMessage());
                }
            }
            
        } catch (Exception e) {
            result.put("status", "error");
            result.put("message", "调试交易哈希失败: " + e.getMessage());
            e.printStackTrace();
        }
        return result;
    }
} 